 /**
 * @author Justin Akin
 * @version Action Pals Core Library 0.1.0
 */
package com.actionpals.utils
{	
	import com.actionpals.enum.Align;
	import com.actionpals.enum.Direction;
	
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	
	/**
	 * Position can be used to calculate the alignment of objects.  It is mainly used to layout
	 * groups of objects that all need to be stacked next to one another in one direction.
	 * 
	 */
	public class PositionUtil
	{
	
	//--------------------------------------------------------------------------------
	//
	//	Public Static Methods
	//
	//--------------------------------------------------------------------------------
		
		/**
		 * 
		 * @param target
		 * @param stackObj
		 * @param direction
		 * @param margin
		 * 
		 */		
		public static function stack( target:DisplayObject, stackObj:DisplayObject, direction:String, margin:Number = 0 ):void
		{
			switch( direction )
			{
				case Direction.ABOVE:
				
					stackAbove( target, stackObj, margin );
					break;
					
				case Direction.BELOW:
				
					stackBelow( target, stackObj, margin );
					break;
					
				case Direction.LEFT:
				
					stackLeft( target, stackObj, margin );
					break;
					
				case Direction.RIGHT:
				
					stackRight( target, stackObj, margin );
					break;
			}
		}
		
		/**
		 * 
		 * @param parentObj
		 * @param direction
		 * @param margin
		 * @param index
		 * 
		 */		
		public static function stackChildren( parentObj:DisplayObjectContainer, direction:String, margin:Number = 0, index:int = 0 ):void
		{
			var len:int = parentObj.numChildren
			var targetChild:DisplayObject;
			var stackChild:DisplayObject;
			
			index = index <= 0 ? 1 : index;
			
			for( var i:int = index; i < len; i++ )
			{
				targetChild = parentObj.getChildAt( i );
				stackChild = parentObj.getChildAt( i - 1 );
				
				stack( targetChild, stackChild, direction, margin );
			}
		}
		
		/**
		 * 
		 * @param target
		 * @param stackObj
		 * @param alignment
		 * @param padding
		 * 
		 */		
		public static function align( target:DisplayObject, stackObj:DisplayObject, alignment:String, padding:Number = 0 ):void
		{
			switch( alignment )
			{
				case Align.TOP:
				
					alignTop( target, stackObj, padding );
					break;
					
				case Align.BOTTOM:
				
					alignBottom( target, stackObj, padding );
					break;
					
				case Align.LEFT:
				
					alignLeft( target, stackObj, padding );
					break;
					
				case Align.RIGHT:
				
					alignRight( target, stackObj, padding );
					break;
					
				case Align.VCENTER:
				
					alignVCenter( target, stackObj, padding );
					break;
					
				case Align.HCENTER:
				
					alignHCenter( target, stackObj, padding );
					break;
			}
		}
		
		/**
		 * 
		 * @param parentObj
		 * @param alignment
		 * @param padding
		 * @param index
		 * 
		 */		
		public static function alignChildren( parentObj:DisplayObjectContainer, alignment:String, padding:Number = 0, index:int = 0 ):void
		{
			var len:int = parentObj.numChildren
			var targetChild:DisplayObject;
			var alignChild:DisplayObject;
			
			index = index <= 0 ? 1 : index;
			
			for( var i:int = index; i < len; i++ )
			{
				targetChild = parentObj.getChildAt( i );
				alignChild = parentObj.getChildAt( i - 1 );
				
				align( targetChild, alignChild, alignment, padding );
			}
		}
		
		/**
		 * 
		 * @param target
		 * @param stackObj
		 * @param margin
		 * 
		 */		
		public static function stackAbove( target:DisplayObject, stackObj:DisplayObject, margin:Number = 0 ):void
		{
			target.y = stackObj.y - target.height - margin;
		}
		
		/**
		 * 
		 * @param target
		 * @param stackObj
		 * @param margin
		 * 
		 */		
		public static function stackBelow( target:DisplayObject, stackObj:DisplayObject, margin:Number = 0 ):void
		{
			target.y = stackObj.y + stackObj.height + margin;
		}
		
		/**
		 * 
		 * @param target
		 * @param stackObj
		 * @param margin
		 * 
		 */		
		public static function stackLeft( target:DisplayObject, stackObj:DisplayObject, margin:Number = 0 ):void
		{
			target.x = stackObj.x - target.width - margin;
		}
		
		/**
		 * 
		 * @param target
		 * @param stackObj
		 * @param margin
		 * 
		 */		
		public static function stackRight( target:DisplayObject, stackObj:DisplayObject, margin:Number = 0 ):void
		{
			target.x = stackObj.x + stackObj.width + margin;
		}
		
		/**
		 * 
		 * @param target
		 * @param alignObj
		 * @param padding
		 * 
		 */		
		public static function alignTop( target:DisplayObject, alignObj:DisplayObject = null, padding:Number = 0 ):void
		{
			var rect:DisplayObject = getAlignRect( target, alignObj );
			target.y = rect.y + padding;
		}
		
		/**
		 * 
		 * @param target
		 * @param alignObj
		 * @param padding
		 * 
		 */		
		public static function alignBottom( target:DisplayObject, alignObj:DisplayObject = null, padding:Number = 0 ):void
		{
			var rect:DisplayObject = getAlignRect( target, alignObj );
			target.y = rect.y + rect.height - target.height - padding;
		}
		
		/**
		 * 
		 * 
		 * @param target
		 * @param alignObj
		 * @param padding
		 */		
		public static function alignLeft( target:DisplayObject, alignObj:DisplayObject = null, padding:Number = 0 ):void
		{
			var rect:DisplayObject = getAlignRect( target, alignObj );
			target.x = rect.x + padding;
		}
		
		/**
		 * 
		 * 
		 * @param target
		 * @param alignObj
		 * @param padding
		 */		
		public static function alignRight( target:DisplayObject, alignObj:DisplayObject = null, padding:Number = 0 ):void
		{
			var rect:DisplayObject = getAlignRect( target, alignObj );
			target.x = rect.x + rect.width - target.width - padding;
		}
		
		/**
		 * 
		 * 
		 * @param target
		 * @param alignObj
		 * @param offSet
		 */		
		public static function alignVCenter( target:DisplayObject, alignObj:DisplayObject = null, offSet:Number = 0, round:Boolean = false ):void
		{
			var rect:DisplayObject = getAlignRect( target, alignObj );
			var value:Number = rect.y + ( ( rect.height - target.height ) / 2 ) + offSet
			target.y = round ? Math.round( value ) : value;
		}
		
		/**
		 * 
		 * 
		 * @param target
		 * @param alignObj
		 * @param offSet
		 */		
		public static function alignHCenter( target:DisplayObject, alignObj:DisplayObject = null, offSet:Number = 0, round:Boolean = false ):void
		{
			var rect:DisplayObject = getAlignRect( target, alignObj );
			var value:Number =  rect.x + ( ( rect.width - target.width ) / 2 ) + offSet;
			target.x = round ? Math.round( value ) : value;
		}
		/**
		 * 
		 * 
		 * @param target
		 * @param alignObj
		 */		
		public static function alignCenter( target:DisplayObject, alignObj:DisplayObject = null, round:Boolean = false ):void
		{
			alignVCenter( target, alignObj, 0, round );
			alignHCenter( target, alignObj, 0, round );
		}
		
		/**
		 * @private
		 */
		private static function getAlignRect( target:DisplayObject, alignObj:DisplayObject ):DisplayObject
		{			
			return alignObj ? alignObj : target.parent;			
		}
	}
}